package com.xiaoma.lock.condition.reponsitory;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Repository {
  /*
   * 仓库的容量
   */
  private int capacity;
  /*
   * 仓库的实际容量
   */
  private int size;
  /*
   * 独占锁对象，相当于synchronized
   */
  private Lock lock;
  /*
   * 仓库满时的条件
   */
  private Condition fullCondition;
  /*
   * 仓库空时的条件
   */
  private Condition emptyCondition;

  public Repository(int capacity) {
    this.capacity = capacity;
    this.size = 0;
    lock = new ReentrantLock();
    fullCondition = lock.newCondition();
    emptyCondition = lock.newCondition();
  }

  /**
   * <p>
   * 生产者生产资源
   *
   * @param produceAmount
   *            生产者预生产量
   */
  public void produce(int produceAmount) {
    //上锁
    lock.lock();
    try {
      while (produceAmount > 0) {

        while (size >= capacity) {
          System.out.println("has fulled!");
          //仓库已经满了，相当于wait()操作，只有当fullCondition.signalAll()才能继续执行
          fullCondition.await();
        }
        /*
         * 获取实际的生产量
         */
        int actAmount = (size + produceAmount) > capacity ? capacity - size : produceAmount;
        size += actAmount;
        System.out.println(
            Thread.currentThread().getName() + ":has + :" + actAmount + ",the actual size is:" + size);
        produceAmount -= actAmount;
        // 通知消费者来消费，相当于notifyAll()操作
        emptyCondition.signalAll();

      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      //释放锁一般放在finally中
      lock.unlock();
    }

  }

  /**
   * <p>
   * 消费者消费资源
   *
   * @param consumeAmount
   *            消费者预消费量
   */
  public void consume(int consumeAmount) {
    lock.lock();
    try {
      while (consumeAmount > 0) {

        while (size <= 0) {
          System.out.println("empty!");
          emptyCondition.await();
        }
        /*
         * 获取实际的消费量
         */
        int actAmount = (size < consumeAmount) ? size : consumeAmount;
        size -= actAmount;
        System.out.println(
            Thread.currentThread().getName() + ":has - :" + actAmount + ",the actual size is:" + size);
        consumeAmount -= actAmount;
        // 通知生产者来生产
        fullCondition.signalAll();
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

  @Override
  public String toString() {
    return "Repository [capacity=" + capacity + ", size=" + size + "]";
  }
}
